# -*- coding: utf-8 -*-
import base64
import json
from collections import OrderedDict

import requests
from Crypto.Hash import SHA
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5
from django.conf import settings

from async import async_job
from common.cache import redis_cache
from common.channel.pay import check_channel_order
from common.order import db as order_db
from common.order.model import PAY_STATUS
from common.utils import track_logging
from common.utils.exceptions import ParamError

_LOGGER = track_logging.getLogger(__name__)

APP_CONF = {
    '6097': {  # witch 支付宝 50-5000
        'gateway': 'https://api.wonderfulsky.com.cn/service',
        'query_gateway': 'https://api.wonderfulsky.com.cn/service',
        'API_KEY': 'BDC0A207BACE3FC2291943C90CF4B2EA',
        'pub_key': """-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0NJar35FO1EnXMsp1cJg
PhyobQnJYKOp4YLRrnsKFUyDf2/EbKmm13Zu0i/nyr79LXqE/YuJL2iAoBTEZ/44
vaj9KQYSUu0VSmQcuPHiFh8rz0EZkQ0ZhO8NqNL6ESVWQUn9jOttB+/F5OtPECWO
C9eiFQVOUDakDOVf2c+ZOS9xAiOu0Gzf6su1NBS1/Gee/YPk3UeugTI5ko0NyV2l
yobVr2B7CR9v0PDsrKbTyZUgZ0xx7rPvJFf6GqxKgwgOjMHQ1cGipxCZ94KNhCrP
sVJl8AO8BYMFU1KJbExQ1Y9UfR1rEiC+GYCf02byNtm7oJxzO+Oi9TuW8fWjE54J
m50ta4O2xT/ro2s36BuRaK90ElBuH1KSOfZlFYU0p+7SIKs75avYl4BKIEH6OcmW
AuyMxmy7mfIgwg2VElTRj1BWdVj7yYZozli4c5mMA+OYUvWvte1ogcXbMm9tXymC
MWf393zvexJDceGrtaNheVKxae7jF9HZ3Iaqdyl6tLEJCGJ5w8khft9PPJXwZo5R
v89AOJ/Jjx7jUdH1QbEeSuG8HDfykHu0SLU6+/Lq46DU2xWpXMhAawfOP1oHjQMa
cWx2bmAya1UZo2h7sNAUwuijEjHuObuPv3gP3tIdxf4fJHlFfNGptNGJ+g3oUtEf
lSglZuU6+2sgNnXMjxldF20CAwEAAQ==
-----END PUBLIC KEY-----""",
        'pri_key': """-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----""",
        'sky_pub': '''-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAy9Oftcu/MAPWfLwZ/VJO
0S+2gRKnlhqcb7KE1phQTcukTT//ObAkWAiZrsXn3TfsiX0py4iiwAFDmI4bylTI
mdZDgp8/9oYnNINfQR9vRqj+NO5R+E1qCTrTlRN5jF2TM6XoN9zqTKABSV5l085Z
RwgG4SAF5Ak0D0g/T9T4I+YWbXo8knDsL6zstHjcZ8cP0dkR8jvyAho5VkD0rF0Y
PUEWCloQOYchwyuJgG798FcwWf5pk0ALd7jWztEd+FB5DktWe5+wkrE+xrCsHX2/
w3RpSc46NU/hd+DjWrLjQDIJnMe9qUop1F+Uc/2z0bUnawMQSt9xAQ+JtySwzbQo
WlOhI5rSqvtDo+7PHexgfR+sda2nuyJZocYL6IVheRXVzEcGpj89E4kimAdssscB
qhmZEHdR+ConCLy+yBLj255fqw0uBoxVwWzRxB08YeCeNf9SwAd4gw5B8MJ73jGF
oQbOWMyxG3OG5m46tPxtGlQOtkU5H/jOJ1BVysRPdAS5feIyb+z9xqsP1aist12O
KnUmElgQ8iouxCS9iUsD4XI+cXGUldP4xeK1bDXCsl4JSvM4lE0dqYvj9qSEl95R
ZRMyJQH6Xoxjg1qL2UWxa9PFqKghgYWbmDlEfmnDvJx8B8EmXhxqvent5JSSffNA
SlD7Jgzi/7DXGWwnMUnB+GUCAwEAAQ==
-----END PUBLIC KEY-----''',
    },
}


def _get_api_key(mch_id):
    return APP_CONF[mch_id]['API_KEY']


def _get_gateway(mch_id):
    return APP_CONF[mch_id]['gateway']


def _get_query_gateway(mch_id):
    return APP_CONF[mch_id]['query_gateway']


def _get_pub_key(mch_id):
    return APP_CONF[mch_id]['pub_key']


def _get_pri_key(mch_id):
    return APP_CONF[mch_id]['pri_key']


def _get_skypub_key(mch_id):
    return APP_CONF[mch_id]['sky_pub']


def _gen_sign(message, the_key):
    key = RSA.importKey(the_key)
    h = SHA.new(message)
    signer = Signature_pkcs1_v1_5.new(key)
    signature = signer.sign(h)
    return base64.b64encode(signature)


def _verify_sign(data, signature, key):
    key = RSA.importKey(key)
    h = SHA.new(data)
    verifier = Signature_pkcs1_v1_5.new(key)
    if verifier.verify(h, base64.b64decode(signature)):
        return True
    return False


def generate_rsa_sign_str(parameter, key):
    s = ''
    for k in sorted(parameter.keys()):
        s += '%s=%s&' % (k.encode('utf8'), parameter[k].encode('utf8'))
    s += str(key)
    return s


def _get_pay_type(service):
    if service == 'alipay':
        return 'alipay'
    elif service == 'wechat':
        return 'wechat'
    elif service == 'wechath5':
        return 'wechath5'
    elif service == 'alipayh5':
        return 'alipayh5'
    return 'alipay'


def _build_form(params, gateway):
    html = u"<head><title>loading...</title></head><form id='submit' name='submit' action='" + gateway + "' method='post'>"
    for k, v in params.items():
        html += "<input type='hidden' name='%s' value='%s'/>" % (k, v)
    html += "</form>"
    html += "<script>doc" \
            "ument.forms['submit'].submit();</script>"
    return html


def create_charge(pay, pay_amount, info):
    service = info.get('service')
    app_id = info['app_id']
    key = _get_api_key(app_id)
    parameter_dict = OrderedDict((
        ('service', 'Payment'),
        ('mid', app_id),
        ('merchantid', str(pay.id)),
        ('amount', str(int(pay_amount))),
        ('currency', 'CNY'),
        ('notifyurl', '{}/pay/api/{}/skypay/{}/'.format(settings.NOTIFY_PREFIX, settings.NOTIFY_PATH, app_id)),
        ('returnurl', '{}/pay/api/{}/skypay/{}'.format(settings.NOTIFY_PREFIX, settings.RETURN_PATH, str(pay.id))),
        ('channel', _get_pay_type(service)),
    ))
    sign_str = generate_rsa_sign_str(parameter_dict, key)
    parameter_dict['sign'] = _gen_sign(sign_str, _get_pri_key(app_id))
    _LOGGER.info("skypay requests data: %s", json.dumps(parameter_dict))
    if service in ('alipayh5', 'alipay'):
        html_text = _build_form(parameter_dict, _get_gateway(app_id))
        cache_id = redis_cache.save_html(pay.id, html_text)
        _LOGGER.info('skypay url: %s', settings.PAY_CACHE_URL + cache_id)
        return {'charge_info': settings.PAY_CACHE_URL + cache_id}
    else:
        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        response = requests.post(_get_gateway(app_id), data=parameter_dict, headers=headers, timeout=5)
        _LOGGER.info("skypay response %s, %s", response.status_code, response.text)
        _LOGGER.info("skypay qrcodeurl: %s", json.loads(response.text)['qrcodeurl'])
        return {'charge_info': json.loads(response.text)['qrcodeurl']}


def verify_notify_sign(params, key, pub_key):
    sign = params['sign']
    params.pop('sign')
    sign_str = generate_rsa_sign_str(params, key)
    if not _verify_sign(sign_str, sign, pub_key):
        _LOGGER.info("skypay sign: %s, sign_str : %s", sign, sign_str)
        raise ParamError('sign not pass, data: %s' % params)


# SUCCESS
def check_notify_sign(request, app_id):
    api_key = _get_api_key(app_id)
    sky_key = _get_skypub_key(app_id)
    data = dict(request.POST.iteritems())
    _LOGGER.info("skypay notify data: %s", data)
    verify_notify_sign(data, api_key, sky_key)
    pay_id = data['merchantid']
    if not pay_id:
        _LOGGER.error("fatal error, out_trade_no not exists, data: %s" % data)
        raise ParamError('skypay event does not contain pay ID')

    pay = order_db.get_pay(int(pay_id))
    if not pay:
        raise ParamError('pay_id: %s invalid' % pay_id)
    if pay.status != PAY_STATUS.READY:
        raise ParamError('pay %s has been processed' % pay_id)

    mch_id = pay.mch_id
    trade_status = data[u'status']
    trade_no = data[u'systemid']
    total_fee = float(data[u'amount'])
    extend = {
        'trade_status': trade_status,
        'trade_no': trade_no,
        'total_fee': total_fee
    }

    check_channel_order(pay_id, total_fee, app_id)

    if trade_status == '1' and total_fee > 0.0:
        _LOGGER.info('skypay check order success, mch_id:%s pay_id:%s' % (mch_id, pay_id))
        order_db.add_pay_success(mch_id, pay_id, total_fee, trade_no, extend)
        # async notify
        async_job.notify_mch(pay_id)


def query_charge(pay_order, app_id):
    pay_id = pay_order.id
    key = _get_api_key(app_id)
    parameter_dict = OrderedDict((
        ('service', 'Order'),
        ('mid', app_id),
        ('merchantid', str(pay_id)),
    ))
    sign_str = generate_rsa_sign_str(parameter_dict, key)
    parameter_dict['sign'] = _gen_sign(sign_str, _get_pri_key(app_id))
    _LOGGER.info("skypay req data: %s", json.dumps(parameter_dict))
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    response = requests.post(_get_query_gateway(app_id), data=parameter_dict, headers=headers, timeout=5)
    _LOGGER.info("skypay query rsp code: %s, data: %s", response.status_code, response.text)

    if response.status_code == 200:
        data = json.loads(response.text)
        trade_status = data['code']
        total_fee = float(data['amount'])
        trade_no = ''
        extend = {
            'trade_status': trade_status,
            'trade_no': trade_no,
            'total_fee': total_fee
        }

        if trade_status == '1000':
            check_channel_order(pay_id, total_fee, app_id)

            _LOGGER.info('skypay query order success, mch_id:%s pay_id:%s' % (pay_order.mch_id, pay_id))
            order_db.add_pay_success(pay_order.mch_id, pay_id, total_fee, trade_no, extend)
            async_job.notify_mch(pay_order.id)
    else:
        _LOGGER.warn('skypay data error, status_code: %s', response.status_code)
